interface ImportCache {
  [key: string]: Promise<any>
}

interface PreloadOptions {
  priority?: 'high' | 'low'
  delay?: number
}

class DynamicImportManager {
  private cache: ImportCache = {}
  private preloadQueue: Array<{ path: string; options: PreloadOptions }> = []
  private isProcessingQueue = false

  async import<T>(path: string): Promise<T> {
    if (path in this.cache) {
      return await this.cache[path]
    }

    this.cache[path] = import(path)
    return await this.cache[path]
  }

  preload(paths: string | string[], options: PreloadOptions = {}) {
    const pathArray = Array.isArray(paths) ? paths : [paths]
    
    pathArray.forEach(path => {
      if (!this.cache[path] && !this.preloadQueue.find(item => item.path === path)) {
        this.preloadQueue.push({ path, options })
      }
    })

    // Sort queue by priority
    this.preloadQueue.sort((a, b) => {
      const priorityA = a.options.priority === 'high' ? 1 : 0
      const priorityB = b.options.priority === 'high' ? 1 : 0
      return priorityB - priorityA
    })

    if (!this.isProcessingQueue) {
      this.scheduleQueueProcessing()
    }
  }

  private scheduleQueueProcessing() {
    if ('requestIdleCallback' in window) {
      requestIdleCallback(() => this.processPreloadQueue(), { timeout: 5000 })
    } else {
      setTimeout(() => this.processPreloadQueue(), 100)
    }
  }

  private async processPreloadQueue() {
    if (this.isProcessingQueue || this.preloadQueue.length === 0) {
      return
    }

    this.isProcessingQueue = true

    while (this.preloadQueue.length > 0) {
      const item = this.preloadQueue.shift()!
      
      try {
        // Apply delay if specified
        if (item.options.delay) {
          await new Promise(resolve => setTimeout(resolve, item.options.delay))
        }

        await this.import(item.path)
        console.log(`Preloaded: ${item.path}`)
      } catch (error) {
        console.warn(`Failed to preload ${item.path}:`, error)
      }

      // Yield control to prevent blocking
      await new Promise(resolve => setTimeout(resolve, 0))
    }

    this.isProcessingQueue = false
  }

  // Clear cache for a specific path or all paths
  clearCache(path?: string) {
    if (path) {
      delete this.cache[path]
    } else {
      this.cache = {}
    }
  }

  // Get cache status
  getCacheStatus() {
    return {
      cached: Object.keys(this.cache).length,
      queued: this.preloadQueue.length,
      processing: this.isProcessingQueue
    }
  }

  // Preload based on user interaction patterns
  preloadOnHover(element: HTMLElement, path: string, options: PreloadOptions = {}) {
    let timeoutId: number

    const handleMouseEnter = () => {
      timeoutId = window.setTimeout(() => {
        this.preload(path, { ...options, priority: 'high' })
      }, 100) // Small delay to avoid preloading on quick mouse movements
    }

    const handleMouseLeave = () => {
      if (timeoutId) {
        clearTimeout(timeoutId)
      }
    }

    element.addEventListener('mouseenter', handleMouseEnter)
    element.addEventListener('mouseleave', handleMouseLeave)

    // Return cleanup function
    return () => {
      element.removeEventListener('mouseenter', handleMouseEnter)
      element.removeEventListener('mouseleave', handleMouseLeave)
      if (timeoutId) {
        clearTimeout(timeoutId)
      }
    }
  }

  // Preload based on viewport intersection
  preloadOnIntersection(element: HTMLElement, path: string, options: PreloadOptions = {}) {
    if (!('IntersectionObserver' in window)) {
      // Fallback for browsers without IntersectionObserver
      this.preload(path, options)
      return () => {}
    }

    const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            this.preload(path, { ...options, priority: 'high' })
            observer.unobserve(element)
          }
        })
      },
      { rootMargin: '50px' } // Start preloading when element is 50px away from viewport
    )

    observer.observe(element)

    return () => {
      observer.unobserve(element)
      observer.disconnect()
    }
  }
}

export const dynamicImportManager = new DynamicImportManager()

// Convenience hooks for React components
export function usePreloadOnHover(path: string, options?: PreloadOptions) {
  return (element: HTMLElement | null) => {
    if (!element) return

    return dynamicImportManager.preloadOnHover(element, path, options)
  }
}

export function usePreloadOnIntersection(path: string, options?: PreloadOptions) {
  return (element: HTMLElement | null) => {
    if (!element) return

    return dynamicImportManager.preloadOnIntersection(element, path, options)
  }
}
